﻿using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using NLog.Web;
using System.Reflection;

namespace HY.Web
{
    public static class BuilderExtension
    {
        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="builder"></param>
        public static void AddLog(this WebApplicationBuilder builder)
        {
            builder.Services.AddLogging(logger =>
            {
                logger.ClearProviders();
                logger.AddNLog("nlog.config");
            });
        }

        /// <summary>
        /// 鉴权
        /// </summary>
        /// <param name="builder"></param>
        public static void AddAuth(this WebApplicationBuilder builder)
        {
            builder.Services.AddSingleton<IAuthorizationHandler, CustomAuthorizationHandler>();
            //自定义鉴权过程中某些类型的返回响应，可在UseStatusCodePagesWithReExecute内统一处理
            //builder.Services.AddSingleton<IAuthorizationMiddlewareResultHandler, CustomAuthorizationMiddlewareResultHandler>();
            builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                            .AddCookie(options =>
                            {
                                options.LoginPath = new PathString("/Home/Login");//没登录跳到这个路径
                                //options.AccessDeniedPath = new PathString("/Home/Error/403");//没权限跳到这个路径，或使用Events自定义处理
                                //options.EventsType = typeof(CustomCookieAuthenticationEvents)//1.配合2处代码每次访问都验证用户是否更改
                                options.Events.OnRedirectToAccessDenied = context =>
                                {
                                    //重写没权限事件，交由UseStatusCodePagesWithReExecute进行全局处理
                                    context.Response.StatusCode = 403;
                                    return Task.CompletedTask;
                                };
                            });
            //builder.Services.AddScoped<CustomCookieAuthenticationEvents>();//2.配合1处代码使用
        }

        #region 依赖注入
        public static void AddIoc(this WebApplicationBuilder builder)
        {
            //自带IOC容器注入
            //builder.Services.AddScoped<DbContext>();
            foreach (var item in GetClass("HY.Service"))
            {
                if (item.Name != "DbContext")
                    builder.Services.AddScoped(item);
            }

            static List<Type> GetClass(string assemblyName)
            {
                if (!String.IsNullOrEmpty(assemblyName))
                {
                    Assembly assembly = Assembly.Load(assemblyName);
                    List<Type> result = assembly.GetExportedTypes().ToList();
                    return result;
                }
                return new List<Type>();
            }

            //替换容器，微软默认的注入方式是DI，替换成Autofac
            //builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
            //builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
            //{
            //    //InstancePerLifetimeScope：同一个Lifetime生成的对象是同一个实例
            //    //SingleInstance：单例模式，每次调用，都会使用同一个实例化的对象；每次都用同一个对象
            //    //InstancePerDependency：默认模式，每次调用，都会重新实例化对象；每次请求都创建一个新的对象
            //    //单独注入
            //    //builder.RegisterType<DbContext>().SingleInstance();

            //    //List<Type> aops = new List<Type>();
            //    //builder.RegisterType<LogAOP>();
            //    //aops.Add(typeof(LogAOP));
            //    //通过程序集注册
            //    Assembly assembly = Assembly.Load("HY.Service");
            //    builder.RegisterAssemblyTypes(assembly)
            //            .InstancePerDependency()//默认模式，每次调用，都会重新实例化对象；每次请求都创建一个新的对象
            //            //.AsImplementedInterfaces()//是以接口方式进行注入,注入这些类的所有的公共接口作为服务（除了释放资源）
            //            //以下为接口方法拦截器，需引用Autofac.Extras.DynamicProxy
            //            //.EnableInterfaceInterceptors()
            //            //.InterceptedBy(aops.ToArray())
            //            ;
            //});
        }

        //public class LogAOP : IInterceptor
        //{
        //    public LogAOP(ILogger<LogAOP> logger)
        //    {
        //        _logger = logger;
        //    }
        //    private readonly ILogger<LogAOP> _logger;
        //    public void Intercept(IInvocation invocation)
        //    {
        //        string dataIntercept = $"【执行方法】：{ invocation.Method.Name}【参数】： {JsonConvert.SerializeObject(invocation.Arguments)}";
        //        try
        //        {
        //            //调用下一个拦截器(若存在)，直到最终的目标方法(Target Method)
        //            invocation.Proceed();
        //            var returnType = invocation.Method.ReturnType;
        //            //异步方法
        //            if (IsAsyncMethod(invocation.Method))
        //            {
        //                if (returnType != null && returnType == typeof(Task))
        //                {
        //                    //等待方法返回的Task
        //                    Func<Task> res = async () => await (Task)invocation.ReturnValue;
        //                    invocation.ReturnValue = res();
        //                }
        //                else //Task<TResult>
        //                {
        //                    var returnType2 = invocation.Method.ReflectedType;//获取返回类型
        //                    if (returnType2 != null)
        //                    {
        //                        var resultType = invocation.Method.ReturnType.GetGenericArguments()[0];
        //                        MethodInfo methodInfo = typeof(LogAOP).GetMethod("HandleAsync", BindingFlags.Instance | BindingFlags.Public)!;
        //                        var mi = methodInfo.MakeGenericMethod(resultType);
        //                        invocation.ReturnValue = mi.Invoke(this, new[] { invocation.ReturnValue });
        //                    }
        //                }
        //                var type = invocation.Method.ReturnType;
        //                var resultProperty = type.GetProperty("Result");
        //                if (resultProperty != null)
        //                    dataIntercept += ($"【结果】：{JsonConvert.SerializeObject(resultProperty.GetValue(invocation.ReturnValue))}\r\n");
        //            }
        //            //同步方法
        //            else if (returnType != null && returnType != typeof(void))
        //            {
        //                dataIntercept += ($"【结果】：{JsonConvert.SerializeObject(invocation.ReturnValue)}\r\n");
        //            }
        //            _logger.LogInformation(dataIntercept);
        //        }
        //        catch (Exception ex)
        //        {
        //            dataIntercept += ($"【结果】：出现异常：{ex.Message + ex.InnerException}\r\n");
        //            _logger.LogError(dataIntercept);
        //            throw;
        //        }
        //    }

        //    /// <summary>
        //    /// 判断是否异步方法
        //    /// </summary>
        //    public static bool IsAsyncMethod(MethodInfo method)
        //    {
        //        return (method.ReturnType == typeof(Task) || (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)));
        //    }
        //}

        #endregion
    }
}
